--              AstroNvim Configuration Table
-- All configuration changes should go inside of the table below

-- You can think of a Lua "table" as a dictionary like data structure the
-- normal format is "key = value". These also handle array like data structures
-- where a value with no key simply has an implicit numeric key
local config = {

  -- Configure AstroNvim updates
  updater = {
    remote = "origin", -- remote to use
    channel = "nightly", -- "stable" or "nightly"
    version = "latest", -- "latest", tag name, or regex search like "v1.*" to only do updates before v2 (STABLE ONLY)
    branch = "main", -- branch name (NIGHTLY ONLY)
    commit = nil, -- commit hash (NIGHTLY ONLY)
    pin_plugins = nil, -- nil, true, false (nil will pin plugins on stable only)
    skip_prompts = false, -- skip prompts about breaking changes
    show_changelog = true, -- show the changelog after performing an update
    auto_reload = false, -- automatically reload and sync packer after a successful update
    auto_quit = false, -- automatically quit the current session after a successful update
    -- remotes = { -- easily add new remotes to track
    --   ["remote_name"] = "https://remote_url.come/repo.git", -- full remote url
    --   ["remote2"] = "github_user/repo", -- GitHub user/repo shortcut,
    --   ["remote3"] = "github_user", -- GitHub user assume AstroNvim fork
    -- },
  },

  -- Set colorscheme to use
  -- colorscheme = "default_theme",
  colorscheme = "onedark",

  -- Add highlight groups in any theme
  highlights = {
    -- init = { -- this table overrides highlights in all themes
    --   Normal = { bg = "#000000" },
    -- }
    -- duskfox = { -- a table of overrides/changes to the duskfox theme
    --   Normal = { bg = "#000000" },
    -- },
  },

  -- set vim options here (vim.<first_key>.<second_key> =  value)
  options = {
    opt = {
      -- set to true or false etc.
      relativenumber = true, -- sets vim.opt.relativenumber
      number = true, -- sets vim.opt.number
      spell = false, -- sets vim.opt.spell
      signcolumn = "yes", -- sets vim.opt.signcolumn to auto
      wrap = false, -- sets vim.opt.wrap
      tabstop = 4,
      shiftwidth = 4,
      expandtab = true,
      colorcolumn = "80",
    },
    g = {
      mapleader = " ", -- sets vim.g.mapleader
      autoformat_enabled = true, -- enable or disable auto formatting at start (lsp.formatting.format_on_save must be enabled)
      cmp_enabled = true, -- enable completion at start
      autopairs_enabled = true, -- enable autopairs at start
      diagnostics_enabled = true, -- enable diagnostics at start
      status_diagnostics_enabled = true, -- enable diagnostics in statusline
      icons_enabled = true, -- disable icons in the UI (disable if no nerd font is available, requires :PackerSync after changing)
    },
  },
  -- If you need more control, you can use the function()...end notation
  -- options = function(local_vim)
  --   local_vim.opt.relativenumber = true
  --   local_vim.g.mapleader = " "
  --   local_vim.opt.whichwrap = vim.opt.whichwrap - { 'b', 's' } -- removing option from list
  --   local_vim.opt.shortmess = vim.opt.shortmess + { I = true } -- add to option list
  --
  --   return local_vim
  -- end,

  -- Set dashboard header
  header = {
    " █████  ███████ ████████ ██████   ██████",
    "██   ██ ██         ██    ██   ██ ██    ██",
    "███████ ███████    ██    ██████  ██    ██",
    "██   ██      ██    ██    ██   ██ ██    ██",
    "██   ██ ███████    ██    ██   ██  ██████",
    " ",
    "    ███    ██ ██    ██ ██ ███    ███",
    "    ████   ██ ██    ██ ██ ████  ████",
    "    ██ ██  ██ ██    ██ ██ ██ ████ ██",
    "    ██  ██ ██  ██  ██  ██ ██  ██  ██",
    "    ██   ████   ████   ██ ██      ██",
  },

  -- Diagnostics configuration (for vim.diagnostics.config({...})) when diagnostics are on
  diagnostics = {
    virtual_text = true,
    underline = true,
    update_in_insert = false,
  },

  -- Extend LSP configuration
  lsp = {
    -- enable servers that you already have installed without mason
    servers = {
      "clangd",
    },
    formatting = {
      -- control auto formatting on save
      format_on_save = {
        enabled = false, -- enable or disable format on save globally
      },
      disabled = { -- disable formatting capabilities for the listed language servers
        -- "sumneko_lua",
      },
      timeout_ms = 1000, -- default format timeout
      -- filter = function(client) -- fully override the default formatting function
      --   return true
      -- end
    },
    -- easily add or disable built in mappings added during LSP attaching
    mappings = {
      n = {
        -- ["<leader>lf"] = false, -- disable formatting keymap
        ["K"] = false,
        ["<F2>"] = {
          function() vim.lsp.buf.rename() end,
          desc = "Rename current symbol",
        },
        ["<leader>lh"] = {
          function() vim.lsp.buf.hover() end,
          desc = "Hover symbol details",
        },
        ["gh"] = {
          function() vim.lsp.buf.hover() end,
          desc = "Hover symbol details",
        },
      },
    },
    -- add to the global LSP on_attach function
    -- on_attach = function(client, bufnr)
    -- end,

    -- override the mason server-registration function
    -- server_registration = function(server, opts)
    --   require("lspconfig")[server].setup(opts)
    -- end,

    -- Add overrides for LSP server settings, the keys are the name of the server
    ["server-settings"] = {
      -- example for addings schemas to yamlls
      -- yamlls = { -- override table for require("lspconfig").yamlls.setup({...})
      --   settings = {
      --     yaml = {
      --       schemas = {
      --         ["http://json.schemastore.org/github-workflow"] = ".github/workflows/*.{yml,yaml}",
      --         ["http://json.schemastore.org/github-action"] = ".github/action.{yml,yaml}",
      --         ["http://json.schemastore.org/ansible-stable-2.9"] = "roles/tasks/*.{yml,yaml}",
      --       },
      --     },
      --   },
      -- },
    },
  },

  -- Mapping data with "desc" stored directly by vim.keymap.set().
  --
  -- Please use this mappings table to set keyboard mapping since this is the
  -- lower level configuration and more robust one. (which-key will
  -- automatically pick-up stored data by this setting.)
  mappings = {
    -- first key is the mode
    n = {
      -- second key is the lefthand side of the map
      -- mappings seen under group name "Buffer"
      ["<leader>bb"] = { "<cmd>tabnew<cr>", desc = "New tab" },
      ["<leader>bc"] = { "<cmd>BufferLinePickClose<cr>", desc = "Pick to close" },
      ["<leader>bj"] = { "<cmd>BufferLinePick<cr>", desc = "Pick to jump" },
      ["<leader>bt"] = { "<cmd>BufferLineSortByTabs<cr>", desc = "Sort by tabs" },

      ["J"] = { "}", desc = "Move up one block" },
      ["K"] = { "{", desc = "Move down one block" },
      ["<A-j>"] = { ":m +1<CR>", desc = "Move text one line down" },
      ["<A-k>"] = { ":m -2<CR>", desc = "Move text one line up" },
      ["<SA-j>"] = { ":copy +0<CR>", desc = "Copy line down" },
      ["<SA-k>"] = { ":copy -1<CR>", desc = "Copy line up" },

      -- ToggleTerm
      ["<C-space>"] = { "<cmd>ToggleTerm size=15 direction=horizontal<cr>", desc = "ToggleTerm horizontal split" },
      -- NeoTree
      ["<C-b>"] = { ":Neotree toggle<CR>", desc = "Toggle Explorer" },
      -- Telescope
      ["<C-p>"] = { ":Telescope find_files<CR>" },
      ["<C-f>"] = { ":Telescope live_grep<CR>" },
      ["<leader>F"] = {
        function()
          require("telescope.builtin").live_grep {
            additional_args = function(args) return vim.list_extend(args, { "--hidden", "--no-ignore" }) end,
          }
        end,
      },
      -- Trouble
      ["<leader>xx"] = { ":TroubleToggle<CR>", desc = "Diagnostics" },
      ["<leader>xw"] = { ":TroubleToggle workspace_diagnostics<CR>", desc = "Workapce Diagnostics" },
      ["<leader>xd"] = { ":TroubleToggle document_diagnostics<CR>", desc = "Document Diagnostics" },
      ["<leader>xq"] = { ":TroubleToggle quickfix<CR>", desc = "Quick Fix" },
      ["gR"] = { "<cmd>TroubleToggle lsp_references<cr>" },
    },
    t = {
      -- setting a mapping to false will disable it
      -- ["<esc>"] = false,
      ["<C-space>"] = { "<cmd>ToggleTerm<cr>", desc = "Close terminal" },
      ["<Esc>"] = { "<C-\\><C-n>" },
    },
  },

  -- Configure plugins
  plugins = {
    init = {
      -- Tabout
      { "Pocco81/auto-save.nvim" },
      -- Auto save
      { "ijimiji/tabout.nvim" },
      -- Trouble
      { "folke/trouble.nvim" },
      -- Vim Surround
      { "tpope/vim-surround" },
      -- Wakatime
      { "wakatime/vim-wakatime" },
      -- Onedark
      {
        "navarasu/onedark.nvim",
        as = "onedark",
        config = function()
          require("onedark").setup {
            style = "darker",
          }
          require("onedark").load()
        end,
      },
    },
    -- All other entries override the require("<key>").setup({...}) call for default plugins
    ["null-ls"] = function(config) -- overrides `require("null-ls").setup(config)`
      -- config variable is the default configuration table for the setup function call
      local null_ls = require "null-ls"

      -- Check supported formatters and linters
      -- https://github.com/jose-elias-alvarez/null-ls.nvim/tree/main/lua/null-ls/builtins/formatting
      -- https://github.com/jose-elias-alvarez/null-ls.nvim/tree/main/lua/null-ls/builtins/diagnostics
      config.sources = {
        -- Set a formatter
        null_ls.builtins.formatting.stylua,
        null_ls.builtins.formatting.prettier,
        null_ls.builtins.formatting.black,
        null_ls.builtins.diagnostics.eslint,
      }
      return config -- return final config table
    end,
    -- treesitter configs
    treesitter = {
      ensure_installed = {
        "lua",
        "vim",
        "c",
        "cpp",
        "lua",
        "rust",
        "python",
        "javascript",
        "typescript",
        "svelte",
        "zig",
      },
    },
    -- use mason-lspconfig to configure LSP installations
    ["mason-lspconfig"] = { -- overrides `require("mason-lspconfig").setup(...)`
      ensure_installed = { "sumneko_lua", "rust_analyzer", "tsserver", "pyright", "zls" },
    },
    -- use mason-null-ls to configure Formatters/Linter installation for null-ls sources
    ["mason-null-ls"] = { -- overrides `require("mason-null-ls").setup(...)`
      ensure_installed = { "prettier", "stylua", "black", "eslint" },
    },

    cmp = function(opts)
      local cmp = require "cmp"
      local luasnip = require "luasnip"
      local types = require "cmp.types"

      -- make cmp sorting more ergonomic
      local function kind_compare(entry1, entry2)
        -- always put text at the end
        local kind1 = entry1:get_kind()
        kind1 = kind1 == types.lsp.CompletionItemKind.Text and 100 or kind1
        local kind2 = entry2:get_kind()
        kind2 = kind2 == types.lsp.CompletionItemKind.Text and 100 or kind2

        -- custom orders for different scenarios
        if kind1 ~= kind2 then
          -- prioritize variable first
          if kind1 == types.lsp.CompletionItemKind.Variable then return true end
          if kind2 == types.lsp.CompletionItemKind.Variable then return false end

          -- don't prioritize non-luasnip snippets
          if kind1 == types.lsp.CompletionItemKind.Snippet and entry1.source:get_debug_name() == "luasnip" then
            return true
          end
          if kind2 == types.lsp.CompletionItemKind.Snippet and entry2.source:get_debug_name() == "luasnip" then
            return false
          end

          local diff = kind1 - kind2
          if diff < 0 then
            return true
          elseif diff > 0 then
            return false
          end
        end
      end

      opts.sorting = {
        comparators = {
          cmp.config.compare.offset,
          cmp.config.compare.exact,
          cmp.config.compare.score,
          kind_compare,
          cmp.config.compare.sort_text,
          cmp.config.compare.length,
          cmp.config.compare.order,
        },
      }

      -- disable cmp in string and comments
      -- TODO: seems to be conflicting with cmp_enabled
      opts.enabled = function()
        -- disable completion in comments
        local context = require "cmp.config.context"
        -- keep command mode completion enabled when cursor is in a comment
        -- if vim.api.nvim_get_mode().mode == "c" then
        -- return true
        -- else
        local not_in_comment = not context.in_treesitter_capture "comment" and not context.in_syntax_group "Comment"
        local not_in_string = not context.in_treesitter_capture "string_literal"
          and not context.in_syntax_group "String"
        return not_in_comment and not_in_string
        -- end
      end

      -- avoid jumping back when a snippet hasn't been finished yet
      luasnip.config.setup {
        region_check_events = "CursorHold,InsertLeave,InsertEnter",
        delete_check_events = "TextChanged,InsertEnter",
      }

      opts.mapping["<Tab>"] = cmp.mapping(function(fallback)
        if cmp.visible() then
          local entry = cmp.get_selected_entry()
          if not entry then
            cmp.select_next_item { behavior = cmp.SelectBehavior.Select }
          else
            cmp.confirm()
          end
        elseif luasnip.expandable() then
          luasnip.expand()
        elseif luasnip.expand_or_jumpable() then
          luasnip.expand_or_jump()
        else
          fallback()
        end
      end, { "i", "s" })

      opts.mapping["<CR>"] = cmp.mapping.confirm { select = true }

      return opts
    end,

    lspkind = {
      mode = "symbol",
    },
  },

  -- LuaSnip Options
  luasnip = {
    -- Add paths for including more VS Code style snippets in luasnip
    vscode_snippet_paths = {},
    -- Extend filetypes
    filetype_extend = {
      -- javascript = { "javascriptreact" },
    },
  },

  -- Modify which-key registration (Use this with mappings table in the above.)
  ["which-key"] = {
    -- Add bindings which show up as group name
    register = {
      -- first key is the mode, n == normal mode
      n = {
        -- second key is the prefix, <leader> prefixes
        ["<leader>"] = {
          -- third key is the key to bring up next level and its displayed
          -- group name in which-key top level menu
          ["b"] = { name = "Buffer" },
          ["x"] = { name = "Trouble" },
        },
      },
    },
  },

  -- This function is run last and is a good place to configuring
  -- augroups/autocommands and custom filetypes also this just pure lua so
  -- anything that doesn't fit in the normal config locations above can go here
  polish = function()
    vim.cmd [[
                au VimLeave,VimSuspend * set guicursor=a:ver25-blinkon250
            ]]
  end,
}

return config
